﻿/*
 * This file contains script types and methods 
 * that are common to all collection templates.
 */
/// <summary>
/// Powerdesigner 字段信息
/// </summary>
public class psField
{
    /// <summary>
    /// 字段ID
    /// </summary>
    public string id = "";
    /// <summary>
    /// 字段编码
    /// </summary>
    public string code = "";
    /// <summary>
    /// 字段名称
    /// </summary>
    public string name = "";
    /// <summary>
    /// 字段类型
    /// </summary>
    public string type = "";
    /// <summary>
    /// 字段长度
    /// </summary>
    public int size = 0;
    /// <summary>
    /// 是否是主键
    /// </summary>
    public bool Identity = false;
    /// <summary>
    /// 是否是必输字段
    /// </summary>
    public bool Mandatory = false;
    /// <summary>
    /// 必输字段
    /// </summary>
    public bool NotNull = false;
}
/// <summary>
/// Powerdesigner 主键信息
/// </summary>
public class psKey
{
    /// <summary>
    /// 主键编码
    /// </summary>
    public string code = "";
    /// <summary>
    /// 主键名称
    /// </summary>
    public string name = "";
    /// <summary>
    /// 唯一索引
    /// </summary>
    public bool Unique;
    /// <summary>
    /// 字段集合
    /// </summary>
    public List<psField> columns = new List<psField>();
}
/// <summary>
/// Powerdesigner 外键信息
/// </summary>
public class psRef
{
    /// <summary>
    /// 外键编码
    /// </summary>
    public string code = "";
    /// <summary>
    /// 外键名称
    /// </summary>
    public string name = "";
    /// <summary>
    /// 外键子节点字段信息
    /// </summary>
    public psField child;
    internal string parentFieldID;
    internal string parentTableID;
    /// <summary>
    /// 外键父节点字段信息
    /// </summary>
    public psField parentField;
    /// <summary>
    /// 外键父节点表
    /// </summary>
    public psTable parentTable;
}
/// <summary>
/// Powerdesigner 表结构
/// </summary>
public class psTable
{
    public List<psField> fields = new List<psField>();
    public List<psRef> references = new List<psRef>();
    public List<psKey> indexes = new List<psKey>();
    public List<psKey> keys = new List<psKey>();
    /// <summary>
    /// 表ID
    /// </summary>
    public string tableid = "";
    /// <summary>
    /// 表名称
    /// </summary>
    public string tableName = "";
    /// <summary>
    /// 表编码
    /// </summary>
    public string tableCode = "";
    /// <summary>
    /// 类名称，即去了表名前缀的编码内容
    /// </summary>
    public string className;
    public bool isStateFlow = false;
    public bool hasIdentity;
    public string PIDField = "";
    public string PIDFieldType = "";
    public bool hasCreator;
    public bool hasCreateTime;
    public bool hasModifier;
    public bool hasModifidate;
    public bool hasVersion;
    public string OrderField = "";
    public bool hasLargeField;
    public string CRCField;
    public string SvrFlag;
    public string Prefix;
}
public class CPowerDesignerFile
{
    public string testInfo = "";
    /// <summary>
    /// 所有表结构信息
    /// </summary>
    public ArrayList tables = new ArrayList();

    public XmlDocument doc;
    public XmlNamespaceManager mng;
    public XmlDocument OpenPowerDesignerFile(string filename)
    {
        doc = new XmlDocument();
        System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite);
        doc.Load(fs);
        mng = new XmlNamespaceManager(doc.NameTable);
        mng.AddNamespace("o", "object");
        mng.AddNamespace("c", "collection");
        mng.AddNamespace("a", "attribute");
        testInfo = "Open a powerdesigner.\n";
        return doc;
    }
    public CPowerDesignerFile(string filename)
    {
        OpenPowerDesignerFile(filename);
        AnalyzeDoc(doc.SelectSingleNode("Model/o:RootObject/c:Children/o:Model", mng));
//        if(fields.Count > 0)return ;
//        foreach(XmlNode pkgNode in doc.SelectNodes("Model/o:RootObject/c:Children/o:Model/c:Packages/o:Package", mng))
//        {
//            AnalyzeDoc(pkgNode, tablename);
//            if(fields.Count > 0)return ;
//        }
    }
    public void AnalyzeDoc(XmlNode packageNode)
    {
        testInfo += "Found " + packageNode.SelectNodes("c:Tables/o:Table", mng).Count.ToString() + " Tables\n";
        foreach(XmlNode tableNode in packageNode.SelectNodes("c:Tables/o:Table", mng))
        {
            #region "发现指定表名，开始分解表结构"
            psTable tbl = new psTable();
            try
            {
                tbl.tableid = tableNode.Attributes["Id"].Value;
                tbl.tableName = tableNode.SelectSingleNode("a:Name", mng).InnerText;
                tbl.tableCode = tableNode.SelectSingleNode("a:Code", mng).InnerText;
                int i = tbl.tableCode.IndexOf('_');
                if(i > 0) tbl.Prefix = tbl.tableCode.Substring(0, i + 1);
                tbl.className = tbl.tableCode.Substring(tbl.Prefix.Length);
            }
            catch(Exception e){
                testInfo += "Table " + tableNode.SelectSingleNode("a:Code", mng).InnerText + " ERROR:" + e.Message + " \n";
            }
            #endregion
            XmlNodeList columns = tableNode.SelectNodes("c:Columns/o:Column", mng);
            testInfo += "Found a table " + tbl.tableName + "(" + tbl.tableCode + ") with " + columns.Count.ToString() + " columns\n";
            #region "取得字段信息"
            foreach(XmlNode columnNode in columns)
            {
                psField fld = new psField();
                fld.id = columnNode.Attributes["Id"].Value;
                foreach(XmlNode subject in columnNode.ChildNodes)
                {
                    if(subject.Name=="a:Name")fld.name = subject.InnerText;
                    if(subject.Name=="a:Code")fld.code = subject.InnerText;
                    if(subject.Name=="a:DataType")fld.type = subject.InnerText;
                    if(subject.Name=="a:Length")fld.size = int.Parse(subject.InnerText);
                    if(subject.Name=="a:Identity"){fld.Identity = true;fld.NotNull=true;}
                    if(subject.Name=="a:Mandatory"){fld.Mandatory = true;fld.NotNull=true;}
                }
                if(fld.code.Length > 2 && fld.code.Substring(0, 3).Equals("CRC", StringComparison.OrdinalIgnoreCase))
                    tbl.CRCField = fld.code;
                else if(fld.code.Equals("SvrFlag", StringComparison.OrdinalIgnoreCase))
                    tbl.SvrFlag = fld.code;
                else if(!fld.code.Equals("SynDate", StringComparison.OrdinalIgnoreCase))
                    tbl.fields.Add(fld);
                tbl.hasIdentity = tbl.hasIdentity || fld.Identity;
                if(fld.code.Equals("PID", StringComparison.OrdinalIgnoreCase) || fld.code.Equals("PIDX", StringComparison.OrdinalIgnoreCase) || fld.code.Equals("ParentID", StringComparison.OrdinalIgnoreCase) || fld.code.Equals("ParentIdx", StringComparison.OrdinalIgnoreCase)){
                    tbl.PIDFieldType =fld.type;
                    tbl.PIDField = fld.code;
                }
                if(fld.code.Equals("ListOrder", StringComparison.OrdinalIgnoreCase) || fld.code.Equals("DisplayOrder", StringComparison.OrdinalIgnoreCase))
                    tbl.OrderField= fld.code;
                tbl.hasCreator = tbl.hasCreator || fld.code.Equals("Creator", StringComparison.OrdinalIgnoreCase) ;
                tbl.hasCreateTime = tbl.hasCreateTime || fld.code.Equals("CreateTime", StringComparison.OrdinalIgnoreCase) ;
                tbl.hasModifier = tbl.hasModifier || fld.code.Equals("Modifier", StringComparison.OrdinalIgnoreCase) ;
                tbl.hasModifidate = tbl.hasModifidate || fld.code.Equals("Modifier", StringComparison.OrdinalIgnoreCase) ;
                tbl.hasVersion = tbl.hasVersion || fld.code.Equals("Version", StringComparison.OrdinalIgnoreCase) || fld.code.Equals("Ver", StringComparison.OrdinalIgnoreCase);
                tbl.isStateFlow = tbl.isStateFlow || fld.code.Equals("FlowIdx", StringComparison.OrdinalIgnoreCase);
                tbl.hasLargeField = tbl.hasLargeField || ".image.text.ntext.".IndexOf(fld.type) > 0;
                testInfo += "Record a field " + fld.code + "(" + fld.name + ")" + tbl.fields.Count.ToString() + "\n";
            }
            #endregion
            #region "取得主键信息"
            XmlNodeList lstkeys = tableNode.SelectNodes("c:Keys/o:Key", mng);
            testInfo += "Found " + columns.Count.ToString() + " PrimaryKeys\n";
            foreach(XmlNode keyNode in lstkeys)
            {
                psKey key = new psKey();
                key.name = keyNode.SelectSingleNode("a:Name", mng).InnerText;
                key.code = keyNode.SelectSingleNode("a:Code", mng).InnerText;
                key.Unique = true;
                if (key.code.StartsWith("PK_")) key.code = key.code.Substring(3);
                if (key.code.StartsWith(tbl.className)) key.code = key.code.Substring(tbl.className.Length);
                key.code = key.code.TrimStart('_');
                if (string.IsNullOrEmpty(key.code)) key.code = "ID";
                foreach (XmlNode keyColumn in keyNode.SelectNodes("c:Key.Columns/o:Column", mng))
                {
                    foreach(psField fld in tbl.fields)
                    {
                        if(fld.id == keyColumn.Attributes["Ref"].Value)
                        {
                            key.columns.Add(fld);
                            fld.NotNull=true;
                            break;
                        }
                    }
                }
                tbl.keys.Add(key);
            }
            #endregion
            #region "取得索引信息"
            lstkeys = tableNode.SelectNodes("c:Indexes/o:Index\n", mng);
            testInfo += "Found " + lstkeys.Count.ToString() + " indexs\n";
            foreach (XmlNode keyNode in lstkeys)
            {
                psKey key = new psKey();
                key.name = keyNode.SelectSingleNode("a:Name", mng).InnerText;
                key.code = keyNode.SelectSingleNode("a:Code", mng).InnerText;
                XmlNode Unique= keyNode.SelectSingleNode("a:Unique", mng);
                key.Unique = Unique == null ?  false : Unique.InnerText == "1";
                if (key.code.StartsWith("IDX_"))key.code = key.code.Substring(4);
                if (key.code.StartsWith(tbl.className)) key.code = key.code.Substring(tbl.className.Length);
                key.code = key.code.TrimStart('_');
                testInfo += "Index " + key.code + "(" + key.Unique.ToString() + ")\n";
                try
                {
                    foreach (XmlNode keyColumn in keyNode.SelectNodes("c:IndexColumns/o:IndexColumn", mng))
                    {
                        XmlNode childNode = keyColumn.SelectSingleNode("c:Column/o:Column", mng);
                        foreach (psField fld in tbl.fields)
                        {
                            if (fld.id == childNode.Attributes["Ref"].Value)
                            {
                                key.columns.Add(fld);
                                fld.NotNull=true;
                                break;
                            }
                        }
                    }
                }
                catch(Exception e){
                    testInfo += "Index " + key.code + " ERROR:" + e.Message + " \n";
                }
                tbl.indexes.Add(key);
            }
            #endregion
            #region "取得外键信息"
            testInfo += "Found " + packageNode.SelectNodes("c:References/o:Reference", mng).Count.ToString() + " References.\n";
            foreach(XmlNode refNode in packageNode.SelectNodes("c:References/o:Reference", mng))
            {
                XmlNode childNode = refNode.SelectSingleNode("c:ChildTable/o:Table", mng);
                if(childNode.Attributes["Ref"].Value == tbl.tableid)
                {
                    psRef r = new psRef();
                    r.name = refNode.SelectSingleNode("a:Name", mng).InnerText;
                    r.code = refNode.SelectSingleNode("a:Code", mng).InnerText;
                    testInfo += "Found a reference " + r.name + "(" + r.code + ") References\n";
                    if (r.code.StartsWith("FK_")) r.code = r.code.Substring(3);
                    if (r.code.StartsWith(tbl.className, StringComparison.OrdinalIgnoreCase)) r.code = r.code.Substring(tbl.className.Length);
                    r.code = r.code.TrimStart('_');
                    r.parentField = new psField();
                    XmlNode fieldNode = refNode.SelectSingleNode("c:Joins/o:ReferenceJoin/c:Object2/o:Column", mng);
                    if (fieldNode == null) continue;
                    try
                    {
                        foreach (psField fld in tbl.fields)               
                        {
                            if (fld.id == fieldNode.Attributes["Ref"].Value)
                            {
                                r.child = fld;
                                fld.NotNull=true;
                                tbl.references.Add(r);
                                r.parentTableID = refNode.SelectSingleNode("c:ParentTable/o:Table", mng).Attributes["Ref"].Value;
                                r.parentFieldID = refNode.SelectSingleNode("c:Joins/o:ReferenceJoin/c:Object1/o:Column", mng).Attributes["Ref"].Value;
                                break;
                            }
                        }
                    }
                    catch(Exception e){
                        testInfo += "Reference " + r.code + " ERROR:" + e.Message + " \n";
                    }
                }
            }
            #endregion
            tables.Add(tbl);
            testInfo += string.Format("---- over of {0} table --- {1} fields, {2} refs, {3} index, {4} keys, CRC={5}, Identity={6}, PID={7}, Order={8}, CRC={9}, SvrFlag={10}",
                tbl.className, tbl.fields.Count, tbl.references.Count, tbl.indexes.Count, tbl.keys.Count, tbl.CRCField, tbl.hasIdentity, tbl.PIDFieldType, tbl.OrderField, tbl.CRCField, tbl.SvrFlag);
        }
        foreach(psTable tbl in tables)
        {
            foreach(psRef r in tbl.references){
                foreach(psTable t in tables)
                {
                    if(r.parentTableID == t.tableid){
                        r.parentTable = t;
                        foreach(psField f in t.fields)
                        {
                            if(r.parentFieldID == f.id){
                                r.parentField = f;
                                break;
                            }
                        }
                        break;
                    }
                }
            }
        }
        testInfo += "end of analyzing.\n";
    }
    /// <summary>
    /// 读取Powerdesinger的所有表明
    /// </summary>
    /// <returns></returns>
    public ArrayList GetTables()
    {
        ArrayList result = new ArrayList();
        foreach(XmlNode tableNode in doc.SelectNodes("Model/o:RootObject/c:Children/o:Model/c:Tables/o:Table", mng))
        {
            result.Add(tableNode.SelectSingleNode("a:Code", mng).InnerText);
        }
        return result;
    }
    public bool isKey(string fld, IList keys){
        testInfo = "";
        foreach(psKey k in keys)
            foreach(psField f in k.columns)
                if(f.code == fld)return true;
        return false;
    }
}